/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package nl.unimaas.games.tron.player.mcts;

import java.util.ArrayList;
import java.util.Iterator;
import nl.unimaas.games.tron.engine.Board;
import nl.unimaas.games.tron.util.LGRTables;

/**
 *
 * @author Cliff Laschet
 */
public class LGRPlayout implements PlayoutStrategy {

    private int boardSize;
    private boolean syncMoves;
    private boolean forgetting;
    private LGRTables lgrTables;
    private int firstMove = -1;
    private int secondMove = -1;
    private ArrayList<Integer> history = new ArrayList<Integer>();
    
    /**
     * 
     * @param boardSize
     * @param alphaRandom
     * @param syncMoves 
     */
    public LGRPlayout(int boardSize, boolean syncMoves, boolean forgetting){
        this.boardSize = boardSize;
        this.syncMoves = syncMoves;
        this.forgetting = forgetting;
        this.lgrTables = new LGRTables(boardSize, forgetting);
    }
    
    /**
     * 
     * @param board
     * @param x
     * @param y
     * @param playerNr
     * @return 
     */
    @Override
    public int getMove(Board board, int x, int y, int playerNr) {
        if(this.syncMoves){
            return getSyncMove(board, x, y, playerNr);
        }else{
            return getASyncMove(board, x, y, playerNr);
        }
    }
    
    /**
     * 
     * @param board
     * @param x
     * @param y
     * @param playerNr
     * @return 
     */
    private int getSyncMove(Board board, int x, int y, int playerNr){
        ArrayList<Integer> moves = board.getValidMovePositions(x, y);
        int move = -1;
        int lastElementIndex = history.size() - 1;
        if (!moves.isEmpty()) {
            if (history.size() >= 2) {
                if (history.size() >= 4) {
                    int secondIndex = lastElementIndex - 2;
                    int firstIndex = lastElementIndex - 3;
                    if (lastElementIndex % 2 == 1) {
                        secondIndex = lastElementIndex;
                        firstIndex = lastElementIndex - 3;
                    }
                    move = this.lgrTables.getLGR2Position(playerNr, history.get(firstIndex), history.get(secondIndex), moves);
                } else {
                    int previousMoveIndex = lastElementIndex - 2;
                    if (lastElementIndex % 2 == 1) {
                        previousMoveIndex = lastElementIndex;
                    }
                    move = this.lgrTables.getLGR1Position(playerNr, history.get(previousMoveIndex), moves);
                }
            }

            if (move != -1) {
                int x2 = Board.posToX(move);
                int y2 = Board.posToY(move);
                history.add(move);
                return Board.getMoveFromPositions(x, y, x2, y2);
            } else {
                int result = PlayoutStrategy.RANDOM.getMove(board, x, y, playerNr);
                move = Board.getPositionFromMove(x, y, result);
                history.add(move);
                return result;
            }
        } else {
            int result = PlayoutStrategy.RANDOM.getMove(board, x, y, playerNr);
            move = Board.getPositionFromMove(x, y, result);
            history.add(move);
            return result;
        }
    }
    
    /**
     * 
     * @param board
     * @param x
     * @param y
     * @param playerNr
     * @return 
     */
    private int getASyncMove(Board board, int x, int y, int playerNr){
        ArrayList<Integer> moves = board.getValidMovePositions(x, y);
        int move = -1;
        if (!moves.isEmpty()) {
            if (secondMove != -1) {
                if (firstMove != -1) {
                    move = this.lgrTables.getLGR2Position(playerNr, firstMove, secondMove, moves);
                }else{
                    move = this.lgrTables.getLGR1Position(playerNr, secondMove, moves);
                }
            }

            if (move != -1) {
                firstMove = secondMove;
                secondMove = move;
                int x2 = Board.posToX(move);
                int y2 = Board.posToY(move);
                history.add(move);
                return Board.getMoveFromPositions(x, y, x2, y2);
            } else {
                int result = PlayoutStrategy.RANDOM.getMove(board, x, y, playerNr);
                move = Board.getPositionFromMove(x, y, result);
                firstMove = secondMove;
                secondMove = move;
                history.add(move);
                return result;
            }
        } else {
            int result = PlayoutStrategy.RANDOM.getMove(board, x, y, playerNr);
            move = Board.getPositionFromMove(x, y, result);
            firstMove = secondMove;
            secondMove = move;
            history.add(move);
            return result;
        }
    }
    
    /**
     * 
     * @param startingPlayer
     * @param rewardPlayer
     * @param reward
     * @param syncMoves 
     */
    public void onFinishPlayout(int startingPlayer, int rewardPlayer, double reward, boolean syncMoves){
        Iterator iterator = history.iterator();
        int[] moveList = new int[history.size()];
        int i = 0;
        while (iterator.hasNext()) {
            moveList[i] = (Integer) iterator.next();
            i++;
        }
        this.lgrTables.update(moveList, startingPlayer, rewardPlayer, reward, syncMoves);
        this.history.clear();
        firstMove = -1;
        secondMove = -1;
    }
    
    public void clearHistory(){
        this.history.clear();
    }
    
    /**
     * 
     */
    public void resetLGRTables(){
        this.lgrTables.resetTables();
        this.firstMove = -1;
        this.secondMove = -1;
        this.clearHistory();
    }
    
    /**
     * 
     * @return 
     */
    public LGRTables getLGRTables(){
        return this.lgrTables;
    }    
    
    /**
     * 
     * @return 
     */
    @Override
    public String toString(){
        return "LGR";
    }
}
